package znet

import (
	"errors"
	"fmt"
	"gin-ranking/common/util"
	"gin-ranking/common/zinx/utils"
	"gin-ranking/common/zinx/ziface"
	"net"
)

type Server struct {
	// 服务器的名称
	Name string
	// 服务器绑定的IP版本
	IPVersion string
	// 服务器监听的IP
	IP string
	// 服务器监听的端口
	Port int
	//// 当前的Server添加一个router，server注册的连接对应的处理业务
	//Router ziface.IRouter

	// 当前 server 的消息管理模块，用来绑定 MsgID 和对应的处理业务 API 关系
	MsgHandler ziface.IMsgHandle

	// 连接管理器
	ConnMgr ziface.IConnManager

	// 创建连接后自动调用的 Hook 函数 OnConnStart
	OnConnStart func(conn ziface.IConnection)

	// 销毁连接前自动调用的 Hook 函数 OnConnStop
	OnConnStop func(conn ziface.IConnection)
}

// CallBackToClient 定义当前客户端连接所绑定的 handleAPI
// (目前这个 handle 写死，以后应该由用户自定义)
func CallBackToClient(conn *net.TCPConn, data []byte, cnt int) error {

	// 回显业务
	fmt.Println("[Conn Handle] CallbackToClient, data:", string(data))
	if _, err := conn.Write(data); err != nil {
		fmt.Println("[Conn Handle] Write Error", err)
		return errors.New("callBackToClient Write Error")
	}
	return nil
}

func (s *Server) Start() {

	fmt.Printf("[Zinx] Server Name: %s, listenner at IP: %s, Port: %d is starting",
		utils.GlobalObject.Name, utils.GlobalObject.Host, utils.GlobalObject.TcpPort)
	fmt.Printf("[Zinx] Version: %s, MaxConn: %d, MaxPackageSize: %d\n",
		utils.GlobalObject.Version, utils.GlobalObject.MaxConn, utils.GlobalObject.MaxPackageSize)

	fmt.Printf("[START] Server Listener at IP :%s, Port %d, is starting\n", s.IP, s.Port)

	go func() {

		// 0 开启消息队列及 worker 工作池
		s.MsgHandler.StartWorkerPool()

		// 1、获取一个TCp的Addr
		addr, err := net.ResolveTCPAddr(s.IPVersion, fmt.Sprintf("%s:%d", s.IP, s.Port))
		if err != nil {
			fmt.Printf("[START] Error resolving tcp address: %s\n", err)
			return
		}

		// 2、监听服务器的地址
		listener, err := net.ListenTCP(s.IPVersion, addr)
		if err != nil {
			fmt.Printf("[START] Error starting tcp listener: %s\n", err)
			return
		}

		// 监听成功
		fmt.Printf("[START] Zinx Server %s success,  listening at IP:%s, port: %d \n", s.Name, s.IP, s.Port)

		// 3、 阻塞等待客户端连接，并处理客户端的读和写
		//var cId uint32 = 0
		for {
			// 3.1、阻塞等待客户端建立连接请求
			conn, err := listener.AcceptTCP()
			if err != nil {
				fmt.Printf("[START] Error accepting tcp connection: %s\n", err)
				continue
			}
			fmt.Println("client connect success", conn.RemoteAddr().String(), "hashCode: ", util.HashCode(conn.RemoteAddr().String()))
			// 3.2 设置服务器最大连接控制,如果超过最大连接，那么则关闭此新的连接
			fmt.Println(">>>>>>ConnMgr Len = ", s.ConnMgr.Len(), ", MAX = ", utils.GlobalObject.MaxConn)
			if s.ConnMgr.Len() >= utils.GlobalObject.MaxConn {
				// TODO 给客户端响应一个超出最大连接的错误包
				fmt.Println("====> Too Many Connections MaxConn = ", utils.GlobalObject.MaxConn)
				conn.Close()
				continue
			}

			//3.3 TODO Server.Start() 处理该新连接请求的 业务 方法， 此时应该有 handler 和 conn是绑定的

			//将处理新连接的业务方法和conn进行绑定，得到我们定义的连接模块
			dealConn := NewConnection(s, conn, util.HashCode(conn.RemoteAddr().String()), s.MsgHandler)

			// 启动当前连接的业务
			go dealConn.Start()
		}
	}()
}

// GetConnMgr 获取当前 server 的连接管理器
func (s *Server) GetConnMgr() ziface.IConnManager {
	return s.ConnMgr
}

// Stop 停止服务
func (s *Server) Stop() {

	fmt.Println("[STOP] Zinx Server, name ", s.Name)

	//  将一些服务器的资源、状态，或者已经开辟的连接信息进行停止或者回收
	s.ConnMgr.ClearConn()
}

func (s *Server) Server() {

	// 启动server服务功能
	s.Start()

	//做一些启动后的业务

	//阻塞状态
	select {}
}

// AddRouter 给当前的服务注册一个路由方法，供客户端的连接处理使用
func (s *Server) AddRouter(msgId uint32, router ziface.IRouter) {
	s.MsgHandler.AddRouter(msgId, router)
	fmt.Println("Add Router Success!")
}

// NewServer 初始化Server模块的方法
func NewServer(name string) *Server {
	s := &Server{
		Name:       utils.GlobalObject.Name,
		IPVersion:  "tcp4",
		IP:         utils.GlobalObject.Host,
		Port:       utils.GlobalObject.TcpPort,
		MsgHandler: NewMsgHandle(),
		ConnMgr:    NewConnManager(),
	}
	return s
}

// SetOnConnStart 注册 Hook 函数
func (s *Server) SetOnConnStart(hookFunc func(conn ziface.IConnection)) {
	s.OnConnStart = hookFunc
}

// SetOnConnStop 注册 Hook 函数
func (s *Server) SetOnConnStop(hookFunc func(conn ziface.IConnection)) {
	s.OnConnStop = hookFunc
}

// CallOnConnStart  调用  Hook 函数
func (s *Server) CallOnConnStart(conn ziface.IConnection) {
	if s.OnConnStart != nil {
		fmt.Println("[CallOnConnStart] Call OnConnStart...")
		s.OnConnStart(conn)
	}
}

// CallOnConnStop  调用  Hook 函数
func (s *Server) CallOnConnStop(conn ziface.IConnection) {
	if s.OnConnStop != nil {
		fmt.Println("[CallOnConnStop] Call OnConnStop...")
		s.OnConnStop(conn)
	}
}
